﻿using Engine;
using Engine.Graphics;
using Game;
using NekoMeko.Common;
using Neorxna;
using Neorxna.Common;
using Neorxna.NUI;
using System;
using System.Linq;
using System.Xml.Linq;

namespace NekoMeko
{
	public class NekoMekoCharacterDialog : Dialog
	{
		public string SettingMode
		{
			get => m_mode;
			set
			{
				if (m_mode != value)
				{
					m_mode = value;
					RefreshList();
				}
			}
		}
		static float FrameHeightToWidth => 350f / 150f;
		static readonly LabelWidget m_linkWarning = new()
		{
			Text = LanguageControl.Get("ContentWidgets", typeof(NekoMekoCharacterDialog).Name, "LinkWarning"),
			FontScale = 0.75f,
			Color = Color.Pink,
			DropShadow = true,
			HorizontalAlignment = WidgetAlignment.Center,
			VerticalAlignment = WidgetAlignment.Near,
			TextAnchor = TextAnchor.HorizontalCenter,
			WordWrap = true,
			Margin = new Vector2(0f, 20f),
		};
		readonly CanvasWidget m_modelFrame;
		readonly PlayerModelWidget m_playerModel;
		readonly NUIStackPanelWidget m_stack;
		readonly ScrollPanelWidget m_scroll;
		readonly BevelledButtonWidget m_changeModel, m_changeSkin, m_ok;
		readonly LabelWidget m_modelName, m_skinName, m_boneSet, m_playerClass;
		readonly NUIFontTextWidget m_description;
		readonly LinkWidget m_modelAuthor, m_skinAuthor;
		readonly PlayerData m_playerData;
		readonly Action<string, string> m_actionWhenOk;
		string m_mode;
		string m_selectedModelKey;
		string m_selectedSkinKey;
		public NekoMekoCharacterDialog(PlayerData playerData, Action<string, string> actionWhenOk, string selectedModelKey = "", string selectedSkinKey = "")
		{
			m_playerData = playerData;
			m_actionWhenOk = actionWhenOk;
			m_selectedModelKey = selectedModelKey;
			m_selectedSkinKey = selectedSkinKey;
			XElement node = ContentManager.Get<XElement>("Dialogs/NekoMekoCharacterDialog");
			LoadContents(this, node);
			m_modelFrame = Children.Find<CanvasWidget>("ModelFrame");
			m_playerModel = Children.Find<PlayerModelWidget>("Model");
			m_stack = Children.Find<NUIStackPanelWidget>("Stack");
			m_scroll = Children.Find<ScrollPanelWidget>("Scroll");
			m_changeModel = Children.Find<BevelledButtonWidget>("ChangeModel");
			m_changeSkin = Children.Find<BevelledButtonWidget>("ChangeSkin");
			m_ok = Children.Find<BevelledButtonWidget>("Ok");
			m_modelName = Children.Find<LabelWidget>("ModelName");
			m_skinName = Children.Find<LabelWidget>("SkinName");
			m_boneSet = Children.Find<LabelWidget>("BoneSet");
			m_playerClass = Children.Find<LabelWidget>("PlayerClass");
			m_description = Children.Find<NUIFontTextWidget>("Description");
			m_modelAuthor = Children.Find<LinkWidget>("ModelAuthor");
			m_skinAuthor = Children.Find<LinkWidget>("SkinAuthor");
			m_playerModel.PlayerClass = PlayerClass.Male;
			m_playerModel.CharacterSkinTexture = ContentManager.Get<Texture2D>("Textures/Creatures/HumanMale1");
			RefreshInfo();
			RefreshList();
		}

		public override void Update()
		{
			base.Update();
			if (Input.Back || Input.Cancel || Children.Find<ButtonWidget>("TopBar.Back").IsClicked)
			{
				DialogsManager.HideDialog(this);
			}
			float height = ScreensManager.RootWidget.ActualSize.Y * 0.5f;
			m_modelFrame.Size = new Vector2(height / FrameHeightToWidth, height);
			if (m_changeModel.IsClicked)
				SettingMode = "Model";
			if (m_changeSkin.IsClicked)
				SettingMode = "Skin";
			m_changeModel.IsChecked = SettingMode == "Model";
			m_changeSkin.IsChecked = SettingMode == "Skin";
			foreach (CanvasWidget canvasWidget in m_stack.Children.Cast<CanvasWidget>())
			{
				PlayerModelWidget playerModelWidget = canvasWidget.Children.Find<PlayerModelWidget>("Model");
				ClickableWidget clickable = canvasWidget.Children.Find<ClickableWidget>("Clickable");
				RectangleWidget check = canvasWidget.Children.Find<RectangleWidget>("Check");
				RectangleWidget background = canvasWidget.Children.Find<RectangleWidget>("Background");
				if (playerModelWidget.ExtraData == null || playerModelWidget.ExtraData is not ExtraData extraData || extraData.Type != "NMM-PlayerModelWidget")
					continue;
				if (extraData.Data is string[] objs && objs.Length == 2)
				{
					bool selected;
					if (SettingMode == "Model")
						selected = objs[0] == m_selectedModelKey;
					else
						selected = objs[1] == m_selectedSkinKey;
					check.IsVisible = selected;
					background.FillColor = selected ? new Color(100, 100, 100, 100) : Color.Transparent;
					if (clickable.IsClicked && !selected)
					{
						if (SettingMode == "Model")
						{
							m_selectedModelKey = objs[0];
							m_selectedSkinKey = NekoMekoDataManager.FindModelData(objs[0])?.DefaultSkinKey ?? string.Empty;
						}
						else
							m_selectedSkinKey = objs[1];
						RefreshInfo();
					}
				}
			}
			if (m_ok.IsClicked)
			{
				m_actionWhenOk?.Invoke(m_selectedModelKey, m_selectedSkinKey);
				DialogsManager.HideDialog(this);
			}
			if (m_modelAuthor.IsClicked)
			{
				NekoResModel nekoResModel = NekoMekoDataManager.FindModelData(m_selectedModelKey);
				if (nekoResModel != null)
				{
					string text = string.Empty;
					foreach (var author in nekoResModel.Authors)
						text += "\n" + author;
					NUIMessageDialog dialog = new(LanguageControl.Get("ContentWidgets", GetType().Name, "ModelAuthor"),
						text, "Ok", null, null);
					foreach (var link in nekoResModel.Links)
					{
						LinkWidget linkWidget = new()
						{
							Text = link, Url = link,
							HorizontalAlignment = WidgetAlignment.Center, VerticalAlignment = WidgetAlignment.Near, TextAnchor = TextAnchor.HorizontalCenter, Margin = new Vector2(0f, 5f),
							FontScale = 0.8f, Color = new Color(64, 192, 64), DropShadow = true
						};
						dialog.AddStackContent(linkWidget);
					}
					dialog.AddStackContent(m_linkWarning);
					DialogsManager.ShowDialog(null, dialog);
				}
			}
			if (m_skinAuthor.IsClicked)
			{
				NekoResSkin nekoResSkin = NekoMekoDataManager.FindSkinData(m_selectedSkinKey);
				if (nekoResSkin != null)
				{
					string text = string.Empty;
					foreach (var author in nekoResSkin.Authors)
						text += "\n" + author;
					NUIMessageDialog dialog = new(LanguageControl.Get("ContentWidgets", GetType().Name, "SkinAuthor"),
						text, "Ok", null, null);
					foreach (var link in nekoResSkin.Links)
					{
						LinkWidget linkWidget = new()
						{
							Text = link, Url = link,
							HorizontalAlignment = WidgetAlignment.Center, VerticalAlignment = WidgetAlignment.Near, TextAnchor = TextAnchor.HorizontalCenter, Margin = new Vector2(0f, 5f),
							FontScale = 0.8f, Color = new Color(64, 192, 64), DropShadow = true
						};
						dialog.AddStackContent(linkWidget);
					}
					dialog.AddStackContent(m_linkWarning);
					DialogsManager.ShowDialog(null, dialog);
				}
			}
		}

		void RefreshInfo()
		{
			if (string.IsNullOrEmpty(m_selectedModelKey) || string.IsNullOrEmpty(m_selectedSkinKey))
				return;
			NekoResModel nekoResModel = NekoMekoDataManager.FindModelData(m_selectedModelKey);
			NekoResSkin nekoResSkin = NekoMekoDataManager.FindSkinData(m_selectedSkinKey);
			if (nekoResModel == null || nekoResSkin == null)
				return;
			//Debug.LogDebug($"model={m_selectedModelKey}, skin={m_selectedSkinKey}");
			m_playerModel.ExtraData = new ExtraData("NMM-PlayerModelWidget")
			{
				Data = new string[2]
				{
					m_selectedModelKey, m_selectedSkinKey
				}
			};
			m_modelName.Text = nekoResModel.DisplayName;
			m_skinName.Text = nekoResSkin.DisplayName;
			m_boneSet.Text = nekoResModel.BoneSet;
			m_playerClass.Text = string.IsNullOrEmpty(nekoResModel.Gender)
				? LanguageControl.Get("ContentWidgets", GetType().Name, "NoLimit")
				: LanguageControl.Get("ContentWidgets", GetType().Name, nekoResModel.Gender);
			m_description.Text = nekoResSkin.Description;
		}
		void RefreshList()
		{
			m_scroll.ScrollPosition = 0f;
			m_stack.ClearChildren();
			if (SettingMode == "Model")
			{
				string playerClass = m_playerData.PlayerClass.ToString();
				foreach (var item in NekoMekoDataManager.AllModelsData)
				{
					string gender = item.Gender;
					if (!string.IsNullOrEmpty(gender) && playerClass != gender)
						continue;
					CanvasWidget widget = new()
					{
						Style = ContentManager.Get<XElement>("Widgets/NMMItem")
					};
					m_stack.AddChildren(widget);
					var playerModelWidget = widget.Children.Find<PlayerModelWidget>("Model");
					playerModelWidget.PlayerClass = PlayerClass.Male;
					playerModelWidget.CharacterSkinTexture = ContentManager.Get<Texture2D>("Textures/Creatures/HumanMale1");
					playerModelWidget.ExtraData = new ExtraData("NMM-PlayerModelWidget")
					{
						Data = new string[2]
						{
							item.Key, NekoMekoDataManager.FindModelData(item.Key)?.DefaultSkinKey ?? string.Empty
						}
					};
					widget.Children.Find<LabelWidget>("Text").Text = item.DisplayName;
				}
			}
			else if (SettingMode == "Skin")
			{
				foreach (var item in NekoMekoDataManager.AllSkinsData)
				{
					if (!item.ModelKeys.Contains(m_selectedModelKey))
						continue;
					CanvasWidget widget = new()
					{
						Style = ContentManager.Get<XElement>("Widgets/NMMItem")
					};
					m_stack.AddChildren(widget);
					var playerModelWidget = widget.Children.Find<PlayerModelWidget>("Model");
					playerModelWidget.PlayerClass = PlayerClass.Male;
					playerModelWidget.CharacterSkinTexture = ContentManager.Get<Texture2D>("Textures/Creatures/HumanMale1");
					playerModelWidget.ExtraData = new ExtraData("NMM-PlayerModelWidget")
					{
						Data = new string[2]
						{
							m_selectedModelKey, item.Key
						}
					};
					widget.Children.Find<LabelWidget>("Text").Text = item.DisplayName;
				}
			}
		}
	}
}
